package com.sbtr.business.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.sbtr.business.feature.entity.*;
import com.sbtr.business.feature.service.FeOperatorService;
import com.sbtr.security.util.RedisUtil;
import com.sbtr.util.BeanCopyUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.lang.ref.SoftReference;
import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;

@Transactional
@EnableScheduling
@Component
public class OperatorUtil {

    //算子id，<字段对应的id，字段>
    String prefix="feature:";
    String data_prefix=prefix+"data:";
    String title_prefix=prefix+"title:";

    @Autowired
    RedisUtil redisUtil;

    private List<LinkedHashMap<String, String>> getRedisData(String key){
        Object o = redisUtil.get(data_prefix+key);
        if(o!=null){
            JSONArray array =JSONUtil.parseArray(o);
            List<LinkedHashMap<String, String>> list = new ArrayList<>();
            array.forEach(r->{
                LinkedHashMap<String, String> params= JSONUtil.toBean(JSONUtil.toJsonStr(r),LinkedHashMap.class);
                list.add(params);
            });
            return list;
        }else {
            return new ArrayList<>();
        }
    }

    private LinkedHashMap<Long, String> getRedisTitle(String key){
        Object o = redisUtil.get(title_prefix+key);
        if(o!=null){
            LinkedHashMap<Long,String> titlesMap = JSONUtil.toBean(JSONUtil.toJsonStr(o),LinkedHashMap.class);
            LinkedHashMap<Long, String> titles = new LinkedHashMap<>();
            if(titlesMap!=null&&titlesMap.size()!=0){
                for (Map.Entry<Long,String> entry:titlesMap.entrySet()){//FIXME 有BUG 必须转换下
                    titles.put(Long.parseLong(String.valueOf(entry.getKey())),entry.getValue());
                }
            }

            return titles;
        }else {
            return new LinkedHashMap<Long, String>();
        }
    }

    /**
     * 根据算子key和指定列获取算子结果
     */
    public List<LinkedHashMap<String, String>> getSelectData(String key, List<String> select) {
        if (getRedisData(key) != null) {
            List<LinkedHashMap<String, String>> list = getRedisData(key);
            List<LinkedHashMap<String, String>> result = new ArrayList<>();
            assert list != null;
            for (Map<String, String> map : list) {

                LinkedHashMap<String, String> params = new LinkedHashMap<>();
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    if (select.contains(entry.getKey())) {
                        params.put(entry.getKey(), entry.getValue());
                    }
                }
                if (params.size() != 0) {
                    result.add(params);
                }
            }
            return result;
        }
        return null;
    }

    public List<List<String>> changeExportHead(List<String> select) {
        List<List<String>> list = ListUtils.newArrayList();
        for (String s : select) {
            List<String> head = ListUtils.newArrayList();
            head.add(s);
            list.add(head);
        }
        return list;
    }

    /**
     * 转换listMap为listList
     */
    public List<List<String>> getArrayData(List<LinkedHashMap<String, String>> list, Boolean containTitle, List<String> select) {
        List<List<String>> r = new ArrayList<>();
        List<String> titles = new ArrayList<>();//标题
        if (CollectionUtils.isNotEmpty(select)) {//指定标题排序并筛选
            titles = select;
        } else if (CollectionUtils.isNotEmpty(list)) {
            titles.addAll(list.get(0).keySet());
        }
        if (containTitle) {
            r.add(titles);
        }
        for (int i = 0; i < list.size(); i++) {
            List<String> params = new ArrayList<>();
            for (int j = 0; j < titles.size(); j++) {//保证顺序一致
                params.add(list.get(i).get(titles.get(j)));
            }
            r.add(params);
        }
        return r;
    }

    /**
     * 转换listMap为listList (列)
     */
    public List<List<String>> getVerticalArrayData(List<LinkedHashMap<String, String>> list, Boolean containTitle, List<String> select) {
        List<List<String>> r = new ArrayList<>();
        List<String> titles = new ArrayList<>();//标题
        if (CollectionUtils.isNotEmpty(select)) {//指定标题排序并筛选
            titles = select;
        } else if (CollectionUtils.isNotEmpty(list)) {
            titles.addAll(list.get(0).keySet());
        }
        if (containTitle) {
            r.add(titles);
        }
        for (int i = 0; i < list.size(); i++) {
            List<String> params = new ArrayList<>();
            for (int j = 0; j < titles.size(); j++) {//保证顺序一致
                params.add(list.get(i).get(titles.get(j)));
            }
            r.add(params);
        }
        return r;
    }

    /**
     * 转换MapList为LISTLIST，竖标题
     *
     * @param params
     * @return
     */
    public List<List<String>> convertVerticalTitle(LinkedHashMap<String, List<Double>> params) {

        List<List<String>> list = new ArrayList<>();
        if (params != null && params.size() > 0) {
            for (Map.Entry<String, List<Double>> entry : params.entrySet()) {
                List<String> data = new ArrayList<>();
                data.add(entry.getKey());
                for (Double param : entry.getValue()) {
                    data.add(param.toString());
                }
                list.add(data);
            }
        }


        return list;
    }


    public List<LinkedHashMap<String, String>> getData(String key) {
        return getRedisData(key);
    }

    public LinkedHashMap<Long, String> getTitle(String key) {
        return getRedisTitle(key);
    }


    public synchronized void putData(String key, List<LinkedHashMap<String, String>> list) {
        redisUtil.set(data_prefix+key, list);
    }

    public synchronized void putTitle(String key, LinkedHashMap<Long, String> title) {
        redisUtil.set(title_prefix+key,title);
    }

    public void clear(String key) {

        redisUtil.del(data_prefix+key);
        redisUtil.del(title_prefix+key);
    }

    public void clears(List<String> keys) {
        keys.forEach(r -> {
            redisUtil.del(data_prefix+r);
            redisUtil.del(title_prefix+r);
        });
    }

    //每天凌晨12点自动清除
    @Scheduled(cron = "0 0 0 * * ?")
    public void autoClear() {
//        data.clear();
//        titles.clear();
        redisUtil.removeByPrex(prefix);
    }



    //获取算子所有子代的id
    private List<Long> returnOpt(List<FeOperator> feOperators, Long pid) {
        List<Long> ids = new ArrayList<>();
        List<Long> ids2 = new ArrayList<>();

        List<FeOperator> last = new ArrayList<>();

        for (FeOperator feOperator : feOperators) {
            if (feOperator.getPid().equals(pid)) {
                ids.add(feOperator.getId());
            } else {
                last.add(feOperator);
            }
        }

        if (CollectionUtil.isNotEmpty(ids)) {
            for (Long id : ids) {
                ids2.addAll(returnOpt(last, id));
            }
        }
        ids2.addAll(ids);

        return ids2;
    }

    private <T extends Model<T>> void batchRMOptRule(List<Long> ids, T t) {
        UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("processing_id", ids);
        t.delete(updateWrapper);
    }
    private void cleanOptData(List<Long> ids){
        //清除处理数据表
        //TODO 加数据处理类型需要加
        if(CollectionUtils.isNotEmpty(ids)){
            batchRMOptRule(ids, new FeFilterRule());
            batchRMOptRule(ids, new FeMissingRule());
            batchRMOptRule(ids, new FeDuplicateRule());
            batchRMOptRule(ids, new FeStandardRule());
            batchRMOptRule(ids, new FePcaRule());
            batchRMOptRule(ids, new FeAttributecreateRule());
        }
    }

//    @PostConstruct
//    public void init(){
//        cleanAllChildren(1684472284307537921L);
//    }

    @Autowired
    FeOperatorService feOperatorService;
    //清除所选画布id所有的数据处理内容
    public void cleanAllChildren(Long id){

        QueryWrapper<FeOperator> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("canvas_id",id);
        List<FeOperator> list = feOperatorService.list(queryWrapper);

        List<Long> ids = list.stream().map(FeOperator::getId).collect(Collectors.toList());

        feOperatorService.removeByIds(ids);
        cleanOptData(ids);
    }

    //清除所选id的list内所有子代的数据处理内容
    public void cleanTreeChildren(List<FeOperator> feOperators,Long id){
        List<Long> ids = returnOpt(feOperators,id);
        cleanOptData(ids);
    }
}
